package wrapper

import (
	"net/http"

	"gitee.com/xxhsjp/x-core/app"
	"gitee.com/xxhsjp/x-core/enums"
	"gitee.com/xxhsjp/x-core/exception"
	"gitee.com/xxhsjp/x-web/response"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type Handler func(ctx *gin.Context) (any, error)

func HandlerFunc(wrapper Handler) gin.HandlerFunc {

	return func(ctx *gin.Context) {

		defer handlePanic(ctx)

		data, err := wrapper(ctx)
		var stdResp response.StdResp
		if err != nil {
			stdResp = handleErr(err)
		} else {
			stdResp.Code = enums.Success.Code
			stdResp.Data = data
		}

		ctx.JSON(http.StatusOK, &stdResp)
	}
}

func handleErr(err error) response.StdResp {
	var stdResp response.StdResp
	if err != nil {
		if bizerror, ok := errors.Cause(err).(exception.BizException); ok {
			logrus.Infof("code: %v err: %+v", bizerror.Code(), bizerror.Error())
			stdResp.Code = bizerror.Code()
			stdResp.Msg = bizerror.Error()
		} else if syserror, ok := errors.Cause(err).(exception.SysException); ok {
			logrus.Errorf("code: %v err: %+v", syserror.SysCode(), syserror)
			stdResp.Code = app.App.Code + enums.SysError.Code
			stdResp.Msg = enums.SysError.Text
		} else {
			logrus.Errorf("code: %v err: %+v", enums.SysError.Code, err)
			stdResp.Code = app.App.Code + enums.SysError.Code
			stdResp.Msg = enums.SysError.Text
		}
	}

	return stdResp
}

func handlePanic(ctx *gin.Context) {
	if err := recover(); err != nil {
		var stdResp response.StdResp
		switch typed := err.(type) {
		case error:
			stdResp = handleErr(typed)
		case string:
			stdResp = handleErr(errors.New(typed))
		default:
			stdResp = handleErr(errors.New(enums.SysError.Text))
		}

		ctx.JSON(http.StatusOK, &stdResp)
	}
}
